import cgi
import time
import google.appengine.ext.webapp.util
import hashlib
import logging
import os
import urlparse
import glp.util
import glp.users
from django.utils import simplejson
from google.appengine.api import mail
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from glp.django.forms import RegistrationForm


class RenderPage(webapp.RequestHandler):
    def get(self):
        if self.request.path == '/dynamic/login-page.html':
            self.HandleLogin()
        elif self.request.path == '/dynamic/login-box.html':
            self.RenderLoginBox()
        elif self.request.path == '/dynamic/request-registration-confirmation.html':
            self.RenderConfirmationRequest()
        elif self.request.path == '/dynamic/user-dump.html':
            self.RenderUserDump()
        else:
            raise NotImplementedError(self.request.path)

    def post(self):
        if self.request.path == '/dynamic/login-page.html':
            self.HandleLogin()
        else:
            raise NotImplementedError(self.request.path)

    def RenderUserDump(self):
        writer = glp.util.ModelDumper(['email', 'first_name', 'last_name', 'school', 'role', 'confirmed', 'created', 'modified', 'registration_id'])
        for user in glp.users.GetUsers():
            writer.add(user)
        glp.util.SimplePage(self.response, writer.render())

    def RenderRegister(self):
        user = users.get_current_user()
        context = {
                'user_email' : user.email(),
                'logout_url' : users.create_logout_url(self.request.uri)
                }
        if glp.users.GetPendingRegistration(user.email()):
            # TODO(sdd): Handle "lost confirmation e-mail"
            self.response.out.write(template.render(
                    "templates/registered_already.html", context))
            return
        if glp.users.GetUser(user.email()):
            # TODO(sdd): Handle "lost confirmation e-mail"
            self.response.out.write(template.render(
                    "templates/registered_already.html", context))
            return
        parent_bits = urlparse.urlparse(self.request.get('parent'))
        if self.request.environ['REQUEST_METHOD'] == 'GET':
            context['registration_form'] = RegistrationForm()
            context['registration_id'] = hashlib.sha1("%s-%s-%d" % (user.email(), self.request.remote_addr, time.time())).hexdigest()
        elif self.request.environ['REQUEST_METHOD'] != 'POST':
            X
        else:
            form = RegistrationForm(data=self.request.POST)
            if form.is_valid():
                registration = form.save(commit=False)
                registration.email = users.get_current_user().email()
                registration.registration_id = self.request.get('registration_id')
                registration.confirmed = False
                registration.put()
                registration_name = '%s %s' % (registration.first_name, registration.last_name)
                context = { 
                    'registration_name' : registration_name,
                    'registration_email' : registration.email,
                    'confirm_url' : '%s://%s/confirm-registration?id=%s' % (parent_bits.scheme, parent_bits.hostname, registration.registration_id)
                    }
                mail_text = template.render("templates/confirm-registration.txt", context)
                mail.send_mail(sender="Rwanda Education Commons Registration Robot <noreply@educationcommons.rw>",
                               to="%s <%s>" % (registration_name, registration.email),
                               subject="Rwanda Education Commons Registration Confirmation",
                               body=mail_text)
                self.redirect('/dynamic/request-registration-confirmation.html?id=%s&parent=%s://%s' % (registration.email, parent_bits.scheme, parent_bits.hostname))
                return
            else:
                context['registration_form'] = form
                context['registration_id'] = self.request.get('registration_id')
        context['post_url'] = '%s?parent=%s://%s' % (self.request.uri, parent_bits.scheme, parent_bits.hostname)
        self.response.out.write(template.render(
                "templates/register.html", context, True))

    def RenderConfirmationRequest(self):
        form_email = self.request.get('id')
        if form_email == None:
            self.redirect('/dynamic/login-page.html')
            return
        registration = glp.users.GetPendingRegistration(form_email)
        if not registration:
            self.redirect('/dynamic/login-page.html')
            return
        self.response.out.write(template.render(
                "templates/confirm-registration.html",
                { 'registration_email' : registration.email }))

    def RenderConfirmation(self):
        parent_bits = urlparse.urlparse(self.request.get('parent'))
        id = cgi.parse_qs(parent_bits.query)['id'][0]
        if not id:
            self.redirect('/dynamic/login-page.html')
            return
        registration = glp.users.ConfirmRegistration(id)
        if not registration:
            self.redirect('/dynamic/login-page.html')
            return
        glp.util.EnqueueTask('users', 'update-membership', registration.email, 'user-manager')
        post_confirm_url = '%s://%s' % (parent_bits.scheme, parent_bits.hostname)
        self.response.out.write(template.render(
                "templates/registration-confirmed.html", {'post_confirm_url' : post_confirm_url }))

    def RenderLoginBox(self):
        user = users.get_current_user()
        glp_user = glp.users.GetUser(user.email()) if user else None
        self.response.out.write(template.render(
                "templates/login-box.html", {
                    'email' : user.email() if user else None,
                    'registered' : True if glp_user else False,
                    'logout_url' :users.create_logout_url(self.request.get('parent'))}))

    def HandleLogin(self):
        user = users.get_current_user()
        glp_user = glp.users.GetUser(user.email()) if user else None
        parent_bits = urlparse.urlparse(self.request.get('parent'))
        if self.request.get('up_mode') == 'confirm':
            self.RenderConfirmation()
        elif self.request.get('up_mode') == 'register':
            if user:
                self.RenderRegister()
            else:
                login_url = users.create_login_url(self.request.uri)
                self.redirect(login_url)
        elif self.request.get('mode') == 'restart' or not self.request.get('mode'):
            gadget_bits = urlparse.urlparse(self.request.url)
            redirect_url = '%s://%s/dynamic/login-page.html?mode=redirect&parent=%s://%s' % (gadget_bits.scheme, gadget_bits.hostname, parent_bits.scheme, parent_bits.hostname)
            login_url = users.create_login_url(redirect_url)
            if user:
                logout_url = users.create_logout_url(login_url)
                self.redirect(logout_url)
            else:
                self.redirect(login_url)
        else:
            parent_prefix = '%s://%s' % (parent_bits.scheme, parent_bits.hostname)
            if glp_user:
                redirect_url = parent_prefix
            elif user:
                redirect_url = parent_prefix + '/register'
            else:
                redirect_url = users.create_login_url(self.request.uri)
            self.response.out.write(template.render(
                    "templates/redirect.html", {'redirect_url' : redirect_url}))


class EnqueueTask(webapp.RequestHandler):
    def get(self):
        tasks = []
        if self.request.path == '/admin/users/rebuild-memberships':
            email = self.request.get('id')
            if email:
                tasks.append(glp.util.EnqueueTask('users', 'update-membership', email, 'user-manager'))
            else:
                authenticator = glp.util.ClientLoginAuthenticator()
                moves = glp.users.ComputeGroupRebuildingTasks(authenticator)
                if moves == None: return
                for move in moves:
                    glp.util.EnqueueDictTask('users', '%s-member' % move[0], {
                            'member_id' : move[1],
                            'group_id' : move[2]}, 'user-manager')
                    tasks.append(move[3])
        else:
            raise NotImplementedError(self.request.path)
        message = ''.join(['%s enqueued.\n' % task for task in tasks])
        glp.util.SimplePage(self.response, message)

class ExecuteTask(webapp.RequestHandler):
    def post(self):
        authenticator = glp.util.ClientLoginAuthenticator()
        if self.request.path == '/tasks/users/update-membership':
            email = self.request.body
            if not email: raise AttributeException('no e-mail specified for membership update')
            if not glp.users.UpdateGroups(authenticator, email):
                logging.info('need session token before updating groups for %s' % email)
        elif self.request.path == '/tasks/users/add-member':
            if not glp.users.AddUserToGroup(authenticator,
                                            self.request.POST.get('member_id'),
                                            self.request.POST.get('group_id')):
                logging.info('need session token before adding %s to %s' % (
                        self.request.POST.get('member_id'),
                        self.request.POST.get('group_id')))
        elif self.request.path == '/tasks/users/remove-member':
            if not glp.users.RemoveUserFromGroup(authenticator,
                                                 self.request.POST.get('member_id'),
                                                 self.request.POST.get('group_id')):
                logging.info('need session token before removing %s from %s' % (
                        self.request.POST.get('member_id'),
                        self.request.POST.get('group_id')))

        else:
            raise NotImplementedError(self.request.path)

class Query(webapp.RequestHandler):
    def get(self):
        if self.request.path == '/admin/users/user':
            user = users.get_current_user()
            email = user.email() if user else None
            if not user:
                state = 'unauthenticated'
            elif glp.users.GetUser(user.email()):
                state = 'registered'
            elif glp.users.GetPendingRegistration(user.email()):
                state = 'unconfirmed'
            else:
                state = 'authenticated'
            self.response.out.write(simplejson.dumps({
                        'email' : email,
                        'state' : state }))
        else:
            raise NotImplementedError(self.request.path)

def main():
    # logging.getLogger().setLevel(logging.DEBUG)
    application = webapp.WSGIApplication([
            ('/dynamic/login-page.html', RenderPage),
            ('/dynamic/login-box.html', RenderPage),
            ('/dynamic/request-registration-confirmation.html', RenderPage),
            ('/dynamic/user-manager.html', RenderPage),
            ('/dynamic/user-dump.html', RenderPage),

            ('/admin/users/rebuild-memberships', EnqueueTask),
            ('/admin/users/remove-member', EnqueueTask),
            ('/admin/users/rebuild-member', EnqueueTask),

            ('/tasks/users/update-membership', ExecuteTask),
            ('/tasks/users/add-member', ExecuteTask),
            ('/tasks/users/remove-member', ExecuteTask),

            ('/admin/users/user', Query)
            ], debug=True)
    google.appengine.ext.webapp.util.run_wsgi_app(application)

if __name__ == "__main__":
    main()
